package com.wry.es.config;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fandow.common.core.pagination.PageInfo;
import com.fandow.common.core.pagination.Paging;
import com.wry.es.dao.OmsOrder;
import com.wry.es.dto.OrderPageDTO;
import com.wry.es.service.impl.HandleOrderService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <h1> QueryInterceptor Mybatis查询拦截器 <h1>
 *
 * @author wry
 * @since 2024/9/2 14:07
 */
@Component
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        })
public class QueryInterceptor implements Interceptor {

    /* 对应上面的args的序号 */
    private final static int MAPPED_STATEMENT_INDEX = 0;
    private final static int PARAMETER_INDEX = 1;
    private final static int ROWBOUNDS_INDEX = 2;
    private final static int RESULT_HANDLER_INDEX = 3;


    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] queryArgs = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
        // 参数
        Object parameter = queryArgs[PARAMETER_INDEX];
        // 替换?实际值 todo
        Map<String, Object> map = (Map<String, Object>) parameter;
        final OrderPageDTO pageDTO = (OrderPageDTO) map.get("pageDTO");
        final PageInfo page = (PageInfo) map.get("page");
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        // sql
        String sql = boundSql.getSql();
        // 方法名
        String name = mappedStatement.getId();
        log.info("拦截的方法名是:" + name + ", sql：" + sql);
        String keyWord = "like";
        if (sql.contains(keyWord) || sql.contains(keyWord.toUpperCase())) {
            final String formatSql = processSql(sql, pageDTO.getOriginalOrderNumber());
            log.info("格式化sql -> " + formatSql);
            final Map<String, String> query = Map.of("query", formatSql);
            final String resp = HttpUtil.post("http://43.136.22.156:9200/_sql?format=json", JSON.toJSONString(query));
            log.info("sql转换es查询结果 -> {}", resp);
            // todo返回有问题 待做
            IPage<OmsOrder> paging = new Page<>();
            paging.setRecords(fromJson(resp));
            return paging;
        }
        return invocation.proceed();
    }

    

    public static List<OmsOrder> fromJson(String json) throws IllegalAccessException {
        JSONObject jsonObject = JSON.parseObject(json);
        JSONArray rowsArray = jsonObject.getJSONArray("rows");
        JSONArray columns = jsonObject.getJSONArray("columns");
        List<OmsOrder> omsOrders = new ArrayList<>();
        int index = 0;
        for (Object rows : rowsArray) {
            JSONArray rowList = (JSONArray) rows;
            OmsOrder omsOrder = new OmsOrder();
            for (Object column : columns) {
                final Object value = rowList.get(index);
                JSONObject columnObj = (JSONObject) column;
                final String fieldName = columnObj.getString("name");
                final String type = columnObj.getString("type");
                // 获取OmsOrder类中的字段
                Field field = null;
                try {
                    field = OmsOrder.class.getDeclaredField(fieldName);
                }catch (Exception e) {
                    e.printStackTrace();
                }
                if (field == null) {
                    index ++;
                    continue;
                }
                // 设置字段可访问
                field.setAccessible(true);
                if ("datetime".equals(type)) {
                    field.set(omsOrder, LocalDateTime.now());
                } else if ("scaled_float".equals(type)) {
                    field.set(omsOrder, new BigDecimal(0));
                } else if ("integer".equals(type)) {
                    field.set(omsOrder, value != null ? Integer.parseInt(value.toString()) : null);
                } else if ("long".equals(type)) {
                    field.set(omsOrder, value != null ? Long.parseLong(value.toString()) : null);
                } else {
                    field.set(omsOrder, value); // 其他类型直接设置
                }
                index ++;
            }
            omsOrders.add(omsOrder);
        }
        return omsOrders;
    }


    public static String processSql(String sql, Object... params) {
        // 第一步：格式化SQL，处理字段名中下划线后的字母变为大写
        sql = formatFields(sql);

        // 第二步：替换SQL中的?占位符
        sql = replacePlaceholders(sql, params);

        // 第三步：处理LIKE CONCAT('%', ?, '%')的情况
        return processConcatLike(sql);
    }

    // 格式化SQL中字段名：将下划线后的字母变为大写
    private static String formatFields(String sql) {
        String[] parts = sql.split("(?i)where", 2);  // 分割 SQL，保持表名部分不变
        if (parts.length < 2) {
            return sql; // 如果没有 WHERE 部分，直接返回原始 SQL
        }
        String beforeWhere = parts[0]; // SELECT ... FROM 部分不做修改
        String afterWhere = parts[1];  // WHERE ... 部分需要处理

        // 正则表达式匹配下划线及其后的字母，处理 WHERE 部分
        Pattern pattern = Pattern.compile("_(\\w)");
        Matcher matcher = pattern.matcher(afterWhere);
        StringBuilder result = new StringBuilder();
        while (matcher.find()) {
            matcher.appendReplacement(result, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(result);

        // 重新组合完整的 SQL 语句
        return beforeWhere + "WHERE " + result;
    }

    // 替换SQL中的?占位符
    private static String replacePlaceholders(String sql, Object... params) {
        int paramIndex = 0;

        // 正则表达式，匹配 ? 占位符
        Pattern questionMarkPattern = Pattern.compile("\\?");
        Matcher questionMarkMatcher = questionMarkPattern.matcher(sql);
        StringBuilder resultSql = new StringBuilder();

        // 替换 ? 为实际参数值
        while (questionMarkMatcher.find() && paramIndex < params.length) {
            String replacement;

            // 判断参数是否为字符串，如果是则加上引号
            if (params[paramIndex] instanceof String) {
                replacement = "'" + params[paramIndex] + "'";
            } else {
                replacement = params[paramIndex].toString();
            }

            questionMarkMatcher.appendReplacement(resultSql, replacement);
            paramIndex++;
        }
        questionMarkMatcher.appendTail(resultSql);

        return resultSql.toString();
    }

    // 处理LIKE CONCAT('%', ?, '%')的转换
    private static String processConcatLike(String sql) {
        // 匹配LIKE CONCAT('%', 'value', '%')，允许前后有空格
        Pattern concatPattern = Pattern.compile("LIKE\\s*CONCAT\\s*\\(\\s*'%',\\s*'(.*?)'\\s*,\\s*'%\\s*'\\s*\\)");
        Matcher concatMatcher = concatPattern.matcher(sql);
        StringBuilder resultSql = new StringBuilder();

        // 将 CONCAT 替换为LIKE '%value%'
        while (concatMatcher.find()) {
            String value = concatMatcher.group(1);  // 获取 CONCAT 中的值
            concatMatcher.appendReplacement(resultSql, "LIKE '%" + value.trim() + "%'");
        }
        concatMatcher.appendTail(resultSql);

        return resultSql.toString();
    }

    // 使用 DSL 进行查询
    private SearchResponse queryElasticsearch(String esQueryDsl) throws IOException {
        // 将 DSL 包装成查询请求
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.wrapperQuery(esQueryDsl));
        SearchRequest searchRequest = new SearchRequest("oms_order"); // 指定索引
        searchRequest.source(sourceBuilder);
        // 执行查询并返回结果
        return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}
